// https://www.uvui.cn/js/http.html
import { ConfigEnum, ContentTypeEnum, MicroServiceEnum } from '@/common/enums/httpEnum'
import $store from '@/store'
// import SingMd5 from '@/common/sign/signMd5'
import { isEmpty, isString } from '@/common/helper/is'
import Platform from '@/common/platform'
import SingSRA from '@/common/sign/signSRA'
import getCurService from './config'
import { AuthError, JoinTimestamp, MessageFun } from './helper'

const { VITE_USER_NODE_ENV } = import.meta.env

const options = {
  messageMode: 'toast', // 'toast'：一般是调用时明确表示不希望自动弹出错误提示|'modal'：的时候会显示modal错误弹窗，而不是消息提示，用于一些比较重要的错误
  // 显示操作成功消息 默认不显示
  showMessage: true,
  // 成功提醒 默认使用后端返回值
  successMsgText: '',
  // 错误提醒 默认使用后端返回值
  errorMsgText: '',
  // 显示失败消息 默认显示
  toastIcon: 'none',
  // messageMode='modal'时的回调
  modalCallBack: null,

  // 显示请求时loading模态框 默认显示
  showLoading: false,
  // loading提醒文字
  loadingMsg: '请求中',

  // 请求链接追加时间戳 '?_t=1712919595382'
  joinTime: true,

  // 接口权限是否需要
  isAuth: false,
  // ...
}

// 此vm参数为页面的实例，可以通过它引用vuex中的变量
export default (vm) => {
  // 初始化请求配置
  uni.$uv.http.setConfig((config) => {
    /* config 为默认全局配置*/
    config.header[ConfigEnum.CONTENT_TYPE] = ContentTypeEnum.FORM_URLENCODED
    // config.header[ConfigEnum.AUTH] = 'szct'
    config.header[ConfigEnum.MICRO_SERVICE_PLATFORM] = MicroServiceEnum.BASE
    config.header[ConfigEnum.APP_PLAT] = Platform.platform

    config.custom = options

    return config
  })

  // 请求拦截
  uni.$uv.http.interceptors.request.use(
    (config) => {
      // console.log('🚀 ~ Request ~ config:', config)
      const { header } = config

      // url=`${domain}${prefix}`
      const { domain, prefix, url } = getCurService(header[ConfigEnum.MICRO_SERVICE_PLATFORM])
      // console.log('🚀 ~ url:', url)

      // #ifdef H5
      config.baseURL = VITE_USER_NODE_ENV === 'development' ? `${prefix}` : `${url}` /* 前缀 */ // 开发模式下根据 baseURL 接口前缀prefix走了 vue.config.js 代理proxy方便调试；发布生成环境时配置为正常`${url}`
      // #endif

      // #ifndef H5
      config.baseURL = `${url}` /* 根域名/前缀 */
      // #endif

      // 可使用async await 做异步操作
      // 初始化请求拦截器时，会执行此方法，此时data为undefined，赋予默认{}
      config.data = config.data || {}
      // 根据custom参数中配置的是否需要token，添加对应的请求头
      // 可以在此通过vm引用vuex中的变量，具体值在vm.$store.state中
      config.header[ConfigEnum.PLATFORM] = Platform.name

      // 需要权限的接口 添加额外请求头
      // if (config.custom.isAuth) {
      config.header[ConfigEnum.TOKEN] = $store.getters.token || ''

      // #ifdef MP-WEIXIN
      // TODO
      // #endif

      // MD5签名模式
      //   config.header[ConfigEnum.TIMESTAMP] = SingMd5.getTimestamp()
      //   config.header[ConfigEnum.SIGNMD5] = SingMd5.createSign(`${config.baseURL}${config.url}`, Object.assign({}, config.params, config.data))

      // SRA签名模式
      config.header[ConfigEnum.SIGNSRA] = SingSRA.rsaEncrypt(`${config.baseURL}${config.url}`)
      //   }

      // start 请求url后追加时间戳
      const params = config.params || {}
      if (!isString(params)) {
        const timestamp = JoinTimestamp(config.custom.joinTime, false)
        config.params = Object.assign(params || {}, timestamp)
      } else {
        // 兼容restful风格
        const timestamp = JoinTimestamp(config.custom.joinTime, true)
        config.url = `${config.url}${params}${timestamp}`
        config.params = undefined
      }
      // end

      // 请求加载loading
      if (config.custom.showLoading) {
        uni.showLoading({ title: config.custom.loadingMsg, mask: true })
      }

      // 需要权限的接口 且没有登录的增加登录拦截
      if (config.custom.isAuth && !$store.getters.token) {
        uni.$Auth()
        return Promise.reject({ ...config, statusCode: 403, errMsg: 'Invalid' })
      }

      return config
    },
    (error) => {
      error?.config?.custom?.showLoading && uni.hideLoading()
      // 可使用async await 做异步操作
      return Promise.reject(error)
    },
  )

  // 响应拦截
  uni.$uv.http.interceptors.response.use(
    (response) => {
      response?.config?.custom?.showLoading && uni.hideLoading()
      /* 对响应成功做点什么 可使用async await 做异步操作*/
      const { data, statusCode } = response

      if (!data) {
        // return '[HTTP] Request has no return value';
        return Promise.reject('请求出错，请稍候重试!')
      }

      // 自定义参数
      const custom = response.config?.custom
      let { errcode, errCode, code, status, errmsg, errMsg, msg, message } = data

      // start 统一高德返回成功状态status为0
      if (response.config.url.includes('amap')) (status = status === '1' ? 0 : status), (data.status = status === '1' ? 0 : status)
      // end

      let Code = errcode !== undefined ? errcode : errCode !== undefined ? errCode : code !== undefined ? code : status !== undefined ? status : statusCode
      if (!isEmpty(Code)) Number(Code) // 转Number

      let Message = errmsg !== undefined ? errmsg : errMsg !== undefined ? errMsg : msg !== undefined ? msg : message !== undefined ? message : ''

      // 在此处根据自己项目的实际情况对不同的errCode执行不同的操作
      if ([2, 401].includes(Code)) {
        // 处理store中用户退出登录&清除token相关
        AuthError()
        return Promise.resolve(data)
      }

      // 这里逻辑可以根据项目进行修改
      const hasSuccess = [0, 200].includes(Code)
      if (hasSuccess) {
        // 是否展示成功提示信息
        custom.showMessage = custom.successMsgText ? custom.showMessage : false
        MessageFun(custom, custom.successMsgText, hasSuccess)
      } else {
        // 是否展示错误提示信息 后台错误主动抛出
        // custom.showMessage = true
        MessageFun(custom, custom.errorMsgText || `${Message}`, hasSuccess)
      }

      return Promise.resolve(data || {})
    },
    (error) => {
      ;(error?.config?.custom?.showLoading || error?.custom?.showLoading) && uni.hideLoading()
      // 对响应错误做点什么 （statusCode !== 200）
      const { config, statusCode, errMsg } = error || {}
      let errorMessage = ''
      try {
        if (statusCode === 403) {
          AuthError()
          return Promise.reject(error)
        }

        if (errMsg.includes('timeout')) errorMessage = '请求超时'
        else if (errMsg.includes('Network')) errorMessage = '网络或接口异常'
        else errorMessage = `${statusCode || '网络异常'}-${errMsg}`

        MessageFun({ messageMode: 'toast', showMessage: true, toastIcon: 'none' }, errorMessage, false)
      } catch (errors) {
        throw new Error(errors)
      }
      return Promise.reject(error)
    },
  )
}
